home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
AmiTCP30b2.lha
/
src
/
appl
/
napsaterm
/
nio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-14
|
25KB
|
1,194 lines
RCS_ID_C="$Id: nio.c,v 3.5 1994/05/14 12:39:24 ppessi Exp $";
/*
* nio.c - Generalized I/O (input from almost anywhere!)
*
* Author: ppessi <Pekka.Pessi@hut.fi>
*
* Copyright (c) 1993 Pekka Pessi
*
* Created : Sun Nov 7 07:45:34 1993 ppessi
* Last modified: Sat May 14 15:38:31 1994 ppessi
*
* $Log: nio.c,v $
* Revision 3.5 1994/05/14 12:39:24 ppessi
* Added support for telnet. Fixed a couple of bugs in rlogin code.
*
* Revision 3.4 1994/02/25 16:08:03 ppessi
* Added the usergroup.library usage
*
* Revision 3.3 1994/02/25 02:04:12 ppessi
* Changed slightly the const defintions for np.title
*
* Revision 3.2 1994/01/08 08:56:33 ppessi
* Removed <stdio.h> from includes
*
* Revision 3.1 94/01/07 22:51:41 ppessi
* Version 3 beta
*
* Revision 2.0 93/11/15 03:42:39 ppessi
* Version 2 initial revision
*
*/
#include "amiga.h"
#include "napsaprefs.h"
#include "nio.h"
#include "display.h"
#include <stdlib.h>
#if USE_SERIAL || USE_STDIO
struct MsgPort *iop = NULL;
#endif
#if USE_SERIAL || USE_STDIO || USE_RLOGIN
#define INBUFSIZE 512
char inbuf[INBUFSIZE];
#endif
char iobuf[BUFSIZE];
int errno;
/*
* Generic functions
*/
long nopen_generic(char **hostvector) { return 0L; }
long nnread_generic(char *buf, long length) { return -1; }
long nwrite_generic(char *buf, long length) { return -1; }
void niosize_generic(ushort s, ushort t, ushort u, ushort v) { }
void nioctl_generic(int code, int arg1, int arg2) { }
void nclose_generic(void) { }
int nabort_generic(void) { return 0; }
/*
* This is a 'virtual function table' for nio
*/
struct niotable {
/* Open nio stream */
long (*nopen)(char **hostvector);
/* Read from nio stream */
long (*nnread)(char *buf, long length);
/* Write to nio stream */
long (*nwrite)(char *buf, long length);
/* Set window size */
void (*niosize)(ushort, ushort, ushort, ushort);
/* Send IOCTL command */
void (*nioctl)(int code, int arg1, int arg2);
/* Close nio stream */
void (*nclose)(void);
/* Abort IO or Resume to IO temporarily */
int (*nabort)(void);
};
extern struct niotable nio_serial;
extern struct niotable nio_stdio;
extern struct niotable nio_dnet;
extern struct niotable nio_rlogin;
extern struct niotable nio_telnet;
struct niotable *niotable =
#if USE_RLOGIN
&nio_rlogin;
enum iotype iotype = rlogin;
#elif USE_TELNET
&nio_telnet;
enum iotype iotype = telnet;
#elif USE_SERIAL
&nio_serial;
enum iotype iotype = serial;
#elif USE_DNET
&nio_dnet;
enum iotype iotype = dnet;
#elif USE_STDIO
&nio_stdio;
enum iotype iotype = stdio;
#else
#error No IO method defined
#endif
/*
* Initialize nioinit structure
*/
void
ninit(enum iotype iotype)
{
switch (iotype) {
#if USE_SERIAL
case serial:
niotable = &nio_serial;
return;
#endif
#if USE_STDIO
case stdio:
niotable = &nio_stdio;
return;
#endif
#if USE_DNET
case dnet:
niotable = &nio_dnet;
return;
#endif
#if USE_RLOGIN
case rlogin:
niotable = &nio_rlogin;
return;
#endif
#if USE_TELNET
case telnet:
niotable = &nio_telnet;
return;
#endif
default:
fatalError("no support for %s in this version",
iotype == serial ? "serial devices" :
(iotype == stdio ? "AmigaDOS IO" :
(iotype == dnet ? "dnet" :
(iotype == telnet ? "telnet" : "rlogin"))));
}
}
/*
* Virtual functions
*/
long nopen(char **hostvector)
{
return (*niotable->nopen)(hostvector);
}
long nnread(char *buf, long length)
{
return (*niotable->nnread)(buf, length);
}
long nwrite(char *buf, long length)
{
return (*niotable->nwrite)(buf, length);
}
void niosize(ushort s, ushort t, ushort u, ushort v)
{
(*niotable->niosize)(s, t, u, v);
}
void nioctl(int code, int arg1, int arg2)
{
(*niotable->nioctl)(code, arg1, arg2);
}
int nabort(void)
{
return (*niotable->nabort)();
}
void nclose(void)
{
(*niotable->nclose)();
}
#if USE_SERIAL
/*
* Define serial IO routines
*/
#include <devices/serial.h>
static int serial_is_open = 0;
static int aborted = 0;
static struct IOExtSer *inreq = NULL, *outreq = NULL;
/*
* Open a nio channel
*/
long nopen_serial(char **hv)
{
if (!(iop = CreateMsgPort()) ||
!(inreq = (struct IOExtSer *)CreateIORequest(iop, sizeof(*inreq))) ||
!(outreq = (struct IOExtSer *)CreateIORequest(iop, sizeof(*outreq))) ||
(inreq->io_SerFlags |= SERF_RAD_BOOGIE|(np.shared ? SERF_SHARED : 0),
OpenDevice(np.device, np.unit, (struct IORequest *)inreq, 0))) {
fatalError("Unable to open %s unit %ld.", np.device, itos(np.unit));
}
serial_is_open = 1;
/* Set speed */
inreq->io_Baud = np.bps;
inreq->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(inreq);
*(outreq) = *(inreq);
inreq->IOSer.io_Command = CMD_READ;
inreq->IOSer.io_Data = (APTR)inbuf;
inreq->IOSer.io_Length = (ULONG)1;
/* inreq->IOSer.io_Flags = IOB_QUICK; */
SendIO((struct IORequest *)inreq);
return 1 << iop->mp_SigBit;
}
/*
* Read characters from line
*/
long nnread_serial(char *buf, long length)
{
long ret, save;
if (GetMsg(iop)) {
buf[0] = inbuf[0] & 127;
inreq->IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)inreq);
save = inreq->IOSer.io_Actual;
if (ret = MIN(inreq->IOSer.io_Actual, length)) {
inreq->IOSer.io_Command = CMD_READ;
inreq->IOSer.io_Data = (APTR)(buf+1);
inreq->IOSer.io_Length = (ULONG)ret;
DoIO((struct IORequest *)inreq);
if (inreq->IOSer.io_Error) {
if (inreq->IOSer.io_Error == 12)
termout("\n**** Serial Buffer Overflow; CLEARING BUFFERS\n", 50);
else
termout("**** Serial Device Error; CLEARING BUFFERS\n", 43);
inreq->IOSer.io_Command = CMD_CLEAR;
DoIO((struct IORequest *)inreq);
}
ret = inreq->IOSer.io_Actual;
}
inreq->IOSer.io_Command = CMD_READ;
inreq->IOSer.io_Data = (APTR)inbuf;
inreq->IOSer.io_Length = (ULONG)1;
SendIO((struct IORequest *)inreq);
return ret + 1;
}
else
return 0;
}
long
nwrite_serial(char *buf, long length)
{
if (!aborted) {
outreq->IOSer.io_Command = CMD_WRITE;
outreq->IOSer.io_Data = (APTR)buf;
outreq->IOSer.io_Length = (ULONG)length;
DoIO((struct IORequest *)outreq);
return (long)outreq->IOSer.io_Actual;
} else {
return length;
}
}
void nioctl_serial(int code, int arg1, int arg2)
{
if (aborted)
return;
if (code == NIO_FLUSH) {
outreq->IOSer.io_Command = CMD_CLEAR;
DoIO((struct IORequest *)outreq);
}
else if (code == NIO_BREAK) {
outreq->IOSer.io_Command = SDCMD_BREAK;
DoIO((struct IORequest *)outreq);
}
}
/*
* Toggle unlisten mode.
* No serial activity may occur until another nabort()
*/
int nabort_serial(void)
{
if (aborted = !aborted) {
if (!CheckIO((struct IORequest *)inreq)) {
AbortIO((struct IORequest *)inreq);
WaitIO((struct IORequest *)inreq);
}
} else {
/* We know that the inreq is aborted */
inreq->IOSer.io_Command = CMD_READ;
inreq->IOSer.io_Data = (APTR)inbuf;
inreq->IOSer.io_Length = (ULONG)1;
inreq->IOSer.io_Flags = IOB_QUICK;
SendIO((struct IORequest *)inreq);
}
return aborted;
}
void nclose_serial(void)
{
if (inreq) {
if (serial_is_open) {
if (!CheckIO((struct IORequest *)inreq)) {
AbortIO((struct IORequest *)inreq);
WaitIO((struct IORequest *)inreq);
}
CloseDevice((struct IORequest *)inreq);
}
DeleteIORequest((struct IORequest *)inreq);
}
if (outreq) {
DeleteIORequest(outreq);
}
if (iop) {
DeleteMsgPort(iop);
}
}
#define niosize_serial niosize_generic
struct niotable nio_serial = {
nopen_serial, nnread_serial, nwrite_serial,
niosize_serial, nioctl_serial, nclose_serial,
nabort_serial,
};
#endif /* USE_SERIAL */
#if USE_DNET
/*
* Define DNET IO routines
*/
#include <local/typedefs.h>
#define DeadKeyConvert do_not_use_DeadKeyConvert
#include <local/suplib_protos.h>
#undef DeadKeyConvert
#include <dnet/channel.h>
#include <lib/dnetlib.h>
#include <server/servers.h>
CHANN *io_chan = NULL;
/*
* Open a nio channel
*/
long nopen_dnet(char **hv)
{
io_chan = (CHANN *)DOpen(NULL, PORT_IALPHATERM, 20, 15);
if(!io_chan) {
fatalError("unable to connect to DNet ALPHATERM port");
}
DQueue(io_chan, 32);
return 1 << ((struct MsgPort *)io_chan)->mp_SigBit;
}
static void handleioctl(short cmd, short val, char aux)
{
static short saverows;
if (iotype == dnet) {
switch (cmd) {
#if 0
case CIO_MODE:
Cooked = val;
break;
#endif
case CIO_SETROWS:
saverows = val;
return;
case CIO_SETCOLS:
dssizewindow(saverows, val, 0);
return;
}
}
}
long nnread_dnet(char *buf, long n)
{
n = DNRead(io_chan, buf, n);
if (n == -2) {
char aux;
short val, cmd;
cmd = DGetIoctl(io_chan, &val, &aux);
if (cmd != -1) {
handleioctl(cmd, val, aux);
}
return 0;
} else
return n;
}
long nwrite_dnet(char *buf, long length)
{
return DWrite(io_chan, buf, length);
}
/*
* Inform the other end of connection about window size changes
*/
void niosize_dnet(ushort ws_row, ushort ws_col,
ushort ws_xpixel, ushort ws_ypixel)
{
DIoctl(io_chan, CIO_SETROWS, ws_row, 0);
DIoctl(io_chan, CIO_SETCOLS, ws_col, 0);
}
/*
* Send ioctl (flush, break &c)
*/
void nioctl_dnet(int code, int arg1, int arg2)
{
DIoctl(io_chan, code, arg1, arg2);
}
void nclose_dnet(void)
{
if (io_chan)
DClose(io_chan);
}
#define nabort_dnet nabort_generic
struct niotable nio_dnet = {
nopen_dnet, nnread_dnet, nwrite_dnet,
niosize_dnet, nioctl_dnet, nclose_dnet,
nabort_dnet,
};
#endif /* USE_DNET */
#if USE_RLOGIN || USE_TELNET
/*
* Common parts for rlogin and telnet
*/
#define BSDSOCKET_H
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <errno.h>
#include <unistd.h>
#include "rlogin.h"
#define ioctl IoctlSocket
/* Prototypes */
#ifdef USE_PRAGMAS
#include <proto/socket.h>
#endif
#ifdef USE_INLINE
#include <inline/socket.h>
#endif
#ifdef USE_CLIB
#include <clib/socket_protos.h>
#endif
struct Library *SocketBase = NULL;
#ifdef USE_GETUID
#ifdef USE_PRAGMAS
#include <proto/usergroup.h>
#elif USE_INLINE
#include <inline/usergroup.h>
#else
#include <clib/usergroup_protos.h>
#endif
#include <pwd.h>
struct Library *UserGroupBase = NULL;
#endif
/*
* Chose a random member of the hostvector
*/
const char *random_host(const char **hostvector)
{
static union {
struct timeval time;
UBYTE bytes[8];
} seed;
const char *host;
int rnd, hosts;
for (hosts = 0; hostvector[hosts]; hosts++)
;
if (hosts == 0)
return NULL;
GetSysTime(&seed.time);
rnd = (seed.bytes[0] + seed.bytes[1] + seed.bytes[2] + seed.bytes[3] +
seed.bytes[4] + seed.bytes[5] + seed.bytes[6] + seed.bytes[7])
% hosts;
host = hostvector[rnd];
/* Remove chosen member */
hostvector[rnd] = hostvector[hosts - 1];
hostvector[hosts - 1] = NULL;
return host;
}
const char termnames[3][6] = { "vt102", "vt52", "h19" };
/* Common global variables */
int rsock = -1;
BYTE IO_bit = -1;
BYTE URG_bit = -1;
ULONG SIGURG = 0;
/* Is it OK to send window size reports */
char okwinch = 0;
/* Current window size */
struct winsize_packet winsize = { 0 };
#endif
#if USE_RLOGIN
/*
* Open a nio channel
*/
long nopen_rlogin(char **hostvector)
{
long iomask;
int true = 1;
struct servent *sp;
char *user, *remote;
char term[32];
const char *host;
SocketBase = OpenLibrary("bsdsocket.library", 3L);
if (!SocketBase) {
fatalError("unable to open BSD socket library");
}
SetErrnoPtr(&errno, sizeof(errno));
IO_bit = AllocSignal(-1);
URG_bit = AllocSignal(-1);
iomask = 1 << IO_bit;
SIGURG = 1 << URG_bit;
SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
sp = getservbyname("login", "tcp");
if (sp == NULL) {
fatalError("login/tcp: unknown service");
}
/* Local username */
#ifdef USE_GETUID
if (UserGroupBase = OpenLibrary(USERGROUPNAME, 2))
{
struct passwd *pw = getpwuid(getuid());
if (pw)
user = pw->pw_name;
else
user = "nobody";
}
else
#endif
{
user = getenv("USER");
if (!user) user = "nobody";
}
/* Our username in remote system */
remote = np.remotename ? np.remotename : user;
/* terminal type is catenated with "/" and line speed */
strcpy(term, np.remoteterm ? np.remoteterm : termnames[np.emulation]);
strncat(term, "/", sizeof(term));
strncat(term, itos(np.bps), sizeof(term));
/* Get the host name to use */
host = random_host(hostvector);
if (host == NULL) {
fatalError("no host specified.");
}
/* Open remote login session */
rsock = rcmd(&host, sp->s_port, user, remote, term, NULL);
if (rsock < 0) {
fatalError("rmcd(): %s", strerror(errno));
}
/* Set title to remote host name */
/* (This has no effect if title is explicitly set) */
if (!np.title) {
np.title = (char *)host;
setnewtitle();
}
/* Set Signal driven IO */
#if USE_FIONBIO
ioctl(rsock, FIONBIO, (char*)&true);
#endif
ioctl(rsock, FIOASYNC, (char*)&true);
true = IPTOS_LOWDELAY;
(void)setsockopt(rsock, IPPROTO_IP, IP_TOS, (char *)&true, sizeof(int));
#ifdef USE_GETUID
/*
* We don't need this any more
*/
if (UserGroupBase) {
CloseLibrary(UserGroupBase);
UserGroupBase = NULL;
}
#endif
return iomask;
}
static int rread(long s, char *buf, int length);
/*
* Read from socket
*/
long nnread_rlogin(char *buf, long length)
{
long n = 0, m;
if (SetSignal(0L, SIGURG) & SIGURG) {
n = rread(rsock, buf, length);
if (n >= 0)
SetSignal(1 << IO_bit, 1 << IO_bit);
return n;
}
for (;;) {
#if USE_FIONBIO
m = recv(rsock, buf + n, length - n, 0);
if (m < 0) {
if (errno == EWOULDBLOCK) {
return n;
} else {
return m;
}
} else if (m == 0) {
/* This may be caused by the remote socket shutdown
* or OOB data delivered to the socket.
*/
ioctl(rsock, SIOCATMARK, (caddr_t)&m);
if (m) {
SetSignal(SIGURG, SIGURG);
}
return n;
}
n += m;
#else
/* Find out how many bytes there are waiting for us */
if (ioctl(rsock, FIONREAD, (char*)&m) < 0) {
perror("nnread FIONREAD");
return -1;
}
if (n + m > length) {
SetSignal(1 << IO_bit, 1 << IO_bit);
m = length - n;
}
if (m == 0)
return n;
m = recv(rsock, buf + n, m, 0);
if (m > 0) {
n += m;
} else {
if (errno == EWOULDBLOCK)
return n;
else
return m; /* error */
}
#endif
}
}
long nwrite_rlogin(char *buf, long length)
{
return send(rsock, buf, length, 0);
}
/*
* Inform the other end of connection about window size changes
*/
void niosize_rlogin(ushort ws_row, ushort ws_col,
ushort ws_xpixel, ushort ws_ypixel)
{
winsize.title[0] = winsize.title[1] = 0377;
winsize.title[2] = winsize.title[3] = 's';
winsize.ws_row = htons(ws_row);
winsize.ws_col = htons(ws_col);
winsize.ws_xpixel = htons(ws_xpixel);
winsize.ws_ypixel = htons(ws_ypixel);
if (okwinch) {
send(rsock, (char *)&winsize, sizeof(winsize), 0);
}
}
void nclose_rlogin(void)
{
if (rsock != -1)
CloseSocket(rsock), rsock = -1;
if (IO_bit != -1)
FreeSignal(IO_bit), IO_bit = -1;
if (URG_bit != -1)
FreeSignal(URG_bit), URG_bit = -1;
if (SocketBase)
CloseLibrary(SocketBase), SocketBase = NULL;
#ifdef USE_GETUID
if (UserGroupBase)
CloseLibrary(UserGroupBase), UserGroupBase = NULL;
#endif
}
/*
* Read next OOB data
*/
static int rread(long s, char *buf, int length)
{
char tiop;
int n = 0, m;
int wasting = 0;
for (;;) {
/* We are at OOB data? */
ioctl(s, SIOCATMARK, (caddr_t)&m);
if (m) {
m = recv(s, &tiop, 1, MSG_OOB);
if (m < 0) break;
if (tiop & TIOCPKT_WINDOW) {
/* Let server know about window size changes */
okwinch = 1;
if (winsize.title[0])
send(rsock, (char *)&winsize, sizeof(winsize), 0);
}
/* Here we might want to handle other bits */
if (tiop & TIOCPKT_FLUSHWRITE) {
for (;;) {
if (ioctl(s, SIOCATMARK, (caddr_t)&m) < 0) {
(void)perror(PROGNAME ": ioctl");
n = -1;
break;
}
if (m) break;
n = recv(s, inbuf, sizeof (inbuf), 0);
if (n <= 0) break;
}
n = 0;
}
#if USE_FIONBIO
/* SIGIO may not be sent for the rest of buffered data */
if (length > 0) {
m = recv(s, buf, length, 0);
if (m >= 0) {
n += m;
return n;
} else if (errno == EWOULDBLOCK) {
return n;
} else {
return -1;
}
}
#else
/* There is a bug in socket code that jams without this.. */
recv(s, inbuf, 0, 0);
#endif
return n;
}
if ((m = recv(s, buf, length, 0)) < 0)
break;
if (wasting)
continue;
n += m; buf +=m; length -= m;
if (length > 0) continue;
wasting = 1; buf = inbuf; length = sizeof(inbuf);
}
return n;
}
#define nioctl_rlogin nioctl_generic
#define nabort_rlogin nabort_generic
struct niotable nio_rlogin = {
nopen_rlogin, nnread_rlogin, nwrite_rlogin,
niosize_rlogin, nioctl_rlogin, nclose_rlogin,
nabort_rlogin,
};
#endif /* USE_RLOGIN */
#if USE_STDIO
/*
* DOS IO routines
*/
struct FileHandle *io_fh;
struct StandardPacket *inpkt = NULL;
/*
* Initialize DOS packet with standard args
*/
static void initpkt(LONG action, ULONG arg1, ULONG arg2)
{
inpkt->sp_Msg.mn_Node.ln_Name = (char *)&(inpkt->sp_Pkt);
inpkt->sp_Pkt.dp_Link = &inpkt->sp_Msg;
inpkt->sp_Pkt.dp_Port = iop;
inpkt->sp_Pkt.dp_Type = action;
inpkt->sp_Pkt.dp_Arg1 = io_fh->fh_Arg1;
inpkt->sp_Pkt.dp_Arg2 = arg1;
inpkt->sp_Pkt.dp_Arg3 = arg2;
}
/*
* Open a nio channel
*/
long nopen_stdio(char **hv)
{
struct Process *me = (struct Process *)FindTask(0L);
io_fh = (struct FileHandle *)BADDR(me->pr_CIS);
iop = CreateMsgPort();
if (iop)
inpkt = (struct StandardPacket *)CreateIORequest(iop, sizeof(*inpkt));
if (!iop || !inpkt) {
fatalError("trouble opening stdin");
}
initpkt(ACTION_WAIT_CHAR, 1000000L, 0);
PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
return 1 << iop->mp_SigBit;
}
long nnread_stdio(char *buf, long length)
{
long ret = 0;
GetMsg(iop);
if (inpkt->sp_Pkt.dp_Res1) {
initpkt(ACTION_READ, (ULONG)inbuf, sizeof(inbuf));
PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
Wait(1 << iop->mp_SigBit);
GetMsg(iop);
ret = inpkt->sp_Pkt.dp_Res1;
if (ret != 0) {
CopyMem(inbuf, buf, ret);
} else {
ret = -1;
}
}
initpkt(ACTION_WAIT_CHAR, 1000000L, 0);
PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
return ret;
}
long nwrite_stdio(char *buf, long length)
{
return Write(Output(), buf, length);
}
void nclose_stdio(void)
{
if (inpkt) {
/* Should we wait for reply? */
WaitPort(iop);
DeleteIORequest(inpkt);
inpkt = NULL;
}
if (iop) {
DeleteMsgPort(iop);
iop = NULL;
}
}
#define niosize_stdio niosize_generic
#define nioctl_stdio nioctl_generic
#define nabort_stdio nabort_generic
struct niotable nio_stdio = {
nopen_stdio, nnread_stdio, nwrite_stdio,
niosize_stdio, nioctl_stdio, nclose_stdio,
nabort_stdio,
};
#endif /* USE_STDIO */
#if USE_TELNET
#include <arpa/telnet.h>
#include "telnet.h"
/*
* Open a nio channel to telnet
*/
long nopen_telnet(char **hostvector)
{
long iomask;
struct servent *sp;
long port;
const char *host;
SocketBase = OpenLibrary("bsdsocket.library", 3L);
if (!SocketBase) {
fatalError("unable to open BSD socket library");
}
SetErrnoPtr(&errno, sizeof errno);
IO_bit = AllocSignal(-1);
URG_bit = AllocSignal(-1);
iomask = 1 << IO_bit;
SIGURG = 1 << URG_bit;
SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
sp = getservbyname(np.service, "tcp");
if (sp == NULL && StrToLong(np.service, &port) <= 0) {
fatalError("%s/tcp: unknown service", np.service);
}
/* Get the host name to use */
host = random_host(hostvector);
if (host == NULL) {
fatalError("no host specified.");
}
/* open telnet session */
if ((rsock = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
struct sockaddr_in addr = { 0 };
struct hostent * h;
int true = 1;
long pid = (long)getpid();
/* Set Signal driven IO */
ioctl(rsock, FIOSETOWN, (caddr_t)&pid);
ioctl(rsock, FIOASYNC, (char*)&true);
setsockopt(rsock, SOL_SOCKET, SO_OOBINLINE, (char *)&true, sizeof(true));
true = IPTOS_LOWDELAY;
setsockopt(rsock, IPPROTO_IP, IP_TOS, (char *)&true, sizeof(true));
addr.sin_family = AF_INET;
if (sp != NULL)
addr.sin_port = sp->s_port;
else
addr.sin_port = port;
if ((h = gethostbyname(host)) == NULL)
fatalError("gethostbyname: %s\n", "no such beast"); /*XXX*/
bcopy(h->h_addr, &addr.sin_addr.s_addr, sizeof (struct in_addr));
if (connect(rsock, (struct sockaddr *)&addr, sizeof addr) == -1)
fatalError("connect: %s\n", strerror(errno));
} else {
fatalError("socket: %s\n", strerror(errno));
}
/* Set title to remote host name */
/* (This has no effect if title is explicitly set) */
if (!np.title) {
np.title = (char *)host;
setnewtitle();
}
return iomask;
}
/*
* Read from socket
*/
long nnread_telnet(char *buf, long length)
{
long n = 0, m;
#if 0 /*XXX*/
if (SetSignal(0L, SIGURG) & SIGURG) {
/* Handle urgent data (SYNC) */
}
#endif
for (;;) {
/* Find out how many bytes there are waiting for us */
if (ioctl(rsock, FIONREAD, (char*)&m) < 0) {
perror("nnread FIONREAD");
return -1;
}
/* If there is too much data for our buffer... */
if (n + m > length) {
/* ... continue, set signal for us */
SetSignal(1 << IO_bit, 1 << IO_bit);
m = length - n;
}
/* No more data, call telnet protocol machine and return */
if (m == 0) {
return telnetdo(buf, n);
}
m = recv(rsock, buf + n, m, 0);
if (m != -1) {
n += m;
} else {
if (errno == EWOULDBLOCK)
/* Call telnet protocol machine and return */
return telnetdo(buf, n);
else
return -1; /* error */
}
}
}
/*
* Write the buffer into telnet
*/
long nwrite_telnet(char *buf, long length)
{
long i;
for (i = 0; i < length; i++) {
register char c = buf[i];
/* We are supposed to quote these */
if (c == 0xff || c == 0x0d) {
/*
* We must quote the buffer
*/
char telnet_buffer[TELNETBUFFERSIZE];
long count;
/*
* If there is a lot of stuff to send, do it without copying
*/
if (i >= TELNETBUFFERSIZE / 2) {
if (send(rsock, buf, i, 0) == -1)
return -1;
count = 0;
} else {
memcpy(telnet_buffer, buf, count = i);
}
/*
* Quote and copy
*/
for (; i < length; i++) {
switch (c = buf[i]) {
case 0xff:
telnet_buffer[count++] = c;
break;
case 0x0d:
telnet_buffer[count++] = c;
c = '\0';
break;
}
telnet_buffer[count++] = c;
/* If our quoting buffer overflows, send it */
if (count >= TELNETBUFFERSIZE - 1) {
if (send(rsock, telnet_buffer, count, 0) == -1)
return -1;
count = 0;
}
}
/* Send the quoted buffer */
if (count > 0 && send(rsock, telnet_buffer, count, 0) == -1)
return -1;
return length;
}
}
/* There was no characters to quote, send as it is */
return send(rsock, buf, length, 0);
}
/*
* Current window size
*/
static ushort ws_row_stored, ws_col_stored;
/*
* Do IAC SB NAWS
*/
extern void do_naws(void)
{
u_char buf[3 + 4 + 4 + 2], *p = buf;
*p++ = IAC;
*p++ = SB;
*p++ = TELOPT_NAWS;
/* We must quote IACs */
if ((ws_col_stored >> 8) == IAC) {
*p++ = IAC;
}
*p++ = ws_col_stored >> 8;
if ((ws_col_stored & 0xff) == IAC) {
*p++ = IAC;
}
*p++ = ws_col_stored & 0xff;
if ((ws_row_stored >> 8) == IAC) {
*p++ = IAC;
}
*p++ = ws_row_stored >> 8;
if ((ws_row_stored & 0xff) == IAC) {
*p++ = IAC;
}
*p++ = ws_row_stored & 0xff;
*p++ = IAC;
*p++ = SE;
send(rsock, buf, p - buf, 0);
}
/*
* Inform the other end of connection about window size changes
*/
void niosize_telnet(ushort ws_row, ushort ws_col,
ushort ws_xpixel, ushort ws_ypixel)
{
/* Store winsize so we can send NAWS after IAC DO NAWS */
ws_row_stored = ws_row;
ws_col_stored = ws_col;
/* Do we have received IAC DO NAWS ? */
if (okwinch) {
do_naws();
}
}
void nclose_telnet(void)
{
if (rsock != -1)
CloseSocket(rsock), rsock = -1;
if (IO_bit != -1)
FreeSignal(IO_bit), IO_bit = -1;
if (URG_bit != -1)
FreeSignal(URG_bit), URG_bit = -1;
if (SocketBase)
CloseLibrary(SocketBase), SocketBase = NULL;
}
#define nioctl_telnet nioctl_generic
#define nabort_telnet nabort_generic
struct niotable nio_telnet = {
nopen_telnet, nnread_telnet, nwrite_telnet,
niosize_telnet, nioctl_telnet, nclose_telnet,
nabort_telnet,
};
#endif /* USE_TELNET */